package dimensional.traveler.client.screens.gamemenu;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.logical.shared.AttachEvent;
import com.google.gwt.event.logical.shared.AttachEvent.Handler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.sencha.gxt.widget.core.client.ContentPanel;
import com.sencha.gxt.widget.core.client.Dialog;
import com.sencha.gxt.widget.core.client.container.BorderLayoutContainer;
import com.sencha.gxt.widget.core.client.container.BorderLayoutContainer.BorderLayoutData;
import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer;
import com.sencha.gxt.widget.core.client.event.HideEvent;
import com.sencha.gxt.widget.core.client.event.HideEvent.HideHandler;
import com.sencha.gxt.widget.core.client.form.TextField;

import dimensional.traveler.client.UserManagement;
import dimensional.traveler.client.mvc.ControllerUtils;
import dimensional.traveler.client.mvc.MediatedController;
import dimensional.traveler.client.services.CareerService;
import dimensional.traveler.client.services.CareerServiceAsync;
import dimensional.traveler.client.services.ServiceAggregator;
import dimensional.traveler.client.services.ServiceAggregatorAsync;
import dimensional.traveler.client.services.UserService;
import dimensional.traveler.client.services.UserServiceAsync;
import dimensional.traveler.client.ui.util.LoadingBar;
import dimensional.traveler.client.ui.util.MessagePopup;
import dimensional.traveler.shared.Settings;
import dimensional.traveler.shared.model.Mission;

public class GameMenuController extends MediatedController implements Handler {

	private Map<String, Mission> newMissionCache = new HashMap<String, Mission>();
	private Map<String, Mission> oldMissionCache = new HashMap<String, Mission>();

	private UserServiceAsync userService = GWT.create(UserService.class);
	private ServiceAggregatorAsync serviceAggregator = GWT.create(ServiceAggregator.class);
	private CareerServiceAsync careerService = GWT.create(CareerService.class);

	private GameMenuScreen screen;

	public void setScreen(GameMenuScreen gameMenuScreen) {
		this.screen = gameMenuScreen;
	}

	public void makeRequests() {
		LoadingBar.showLoadingBar();

		serviceAggregator.getGameMenuData(UserManagement.getLoggedInUser(), new AsyncCallback<Map<String, Object>>() {

			@Override
			public void onSuccess(Map<String, Object> result) {
				@SuppressWarnings("unchecked")
				Collection<Mission> newMissions = (Collection<Mission>) result.get(Settings.NEW_MISSIONS_KEY);
				processNewMissions(newMissions);
				@SuppressWarnings("unchecked")
				Collection<Mission> oldMissions = (Collection<Mission>) result.get(Settings.OLD_MISSIONS_KEY);
				processOldMissions(oldMissions);

				LoadingBar.hideLoadingBar();

			}

			@Override
			public void onFailure(Throwable caught) {
				handleRequestFailure(caught);
			}
		});
	}

	private void processNewMissions(Collection<Mission> newMissions) {
		newMissionCache.clear();
		for (Mission mission : newMissions) {
			newMissionCache.put(mission.getMissionId(), mission);
		}
		screen.setupNewMissions(newMissions);
	}

	private void processOldMissions(Collection<Mission> result) {
		oldMissionCache.clear();
		for (Mission mission : result) {
			oldMissionCache.put(mission.getMissionId(), mission);
		}
		screen.setupOldMissions(result);
	}

	public Mission getNewMissionById(String id) {
		return newMissionCache.get(id);
	}

	public Mission getOldMissionById(String id) {
		return oldMissionCache.get(id);
	}

	class SaveDialog implements HideEvent.HasHideHandlers {

		final Dialog saveDialog = new Dialog();
		final TextField newSaveGame = new TextField();
		final VerticalLayoutContainer saveGameContainer = new VerticalLayoutContainer();

		SaveDialog() {
			saveDialog.setBodyBorder(false);
			saveDialog.setHeadingText("Save your game");
			saveDialog.setWidth(400);
			saveDialog.setHeight(225);
			saveDialog.setHideOnButtonClick(true);
			saveDialog.setModal(true);

			BorderLayoutContainer layout = new BorderLayoutContainer();

			saveDialog.add(layout);

			// center
			ContentPanel centerPanel = new ContentPanel();
			centerPanel.setHeadingText("Your saves");
			layout.setCenterWidget(centerPanel);

			ScrollPanel scrollPanel = new ScrollPanel();
			scrollPanel.add(saveGameContainer);
			centerPanel.add(scrollPanel);

			ContentPanel southPanel = new ContentPanel();
			BorderLayoutData data = new BorderLayoutData(60);
			southPanel.setLayoutData(data);
			southPanel.setHeadingText("New save");
			layout.setSouthWidget(southPanel);

			newSaveGame.setEmptyText("new save");

			southPanel.add(newSaveGame);
		}

		void show(List<String> saveGames) {
			saveGameContainer.clear();
			for (String saveGame : saveGames) {
				saveGameContainer.add(new Label(saveGame));
			}
			saveDialog.show();
			newSaveGame.focus();
		}

		@Override
		public HandlerRegistration addHideHandler(HideHandler handler) {
			return saveDialog.addHideHandler(handler);
		}

		boolean wasClosedByOkButton() {
			return saveDialog.getHideButton() != null && "OK".equals(saveDialog.getHideButton().getText());
		}

		String getSaveGameName() {
			return newSaveGame.getText();
		}

	}
	
	private final SaveDialog saveDialog = new SaveDialog();

	void showSaveSuccessMessage() {
		MessagePopup.displayInfoMessage("Game saved", "Your game has been saved");
	}
	
	public void saveProgress() {

		showSavedGames(saveDialog);

		saveDialog.addHideHandler(new HideHandler() {

			@Override
			public void onHide(HideEvent event) {
				if (saveDialog.wasClosedByOkButton()) {
					String saveGameName = saveDialog.getSaveGameName();
					careerService.saveProgress(UserManagement.getLoggedInUser(), saveGameName, new AsyncCallback<Void>() {

						@Override
						public void onSuccess(Void result) {
							showSaveSuccessMessage();
						}

						@Override
						public void onFailure(Throwable caught) {
							handleRequestFailure(caught);
						}
					});
				}
			}
		});

	}

	private void showSavedGames(final SaveDialog saveDialog) {
		userService.getSavedGamesForUser(UserManagement.getLoggedInUser(), new AsyncCallback<List<String>>() {
			@Override
			public void onSuccess(List<String> result) {
				saveDialog.show(result);
			}

			@Override
			public void onFailure(Throwable caught) {
				handleRequestFailure(caught);
			}
		});
	}

	public void saveProgressAndExit() {
		showSavedGames(saveDialog);

		saveDialog.addHideHandler(new HideHandler() {

			@Override
			public void onHide(HideEvent event) {
				if (saveDialog.wasClosedByOkButton()) {
					String saveGameName = saveDialog.getSaveGameName();
					careerService.saveProgress(UserManagement.getLoggedInUser(), saveGameName, new AsyncCallback<Void>() {

						@Override
						public void onSuccess(Void result) {
							showSaveSuccessMessage();
							exitGame();
						}

						@Override
						public void onFailure(Throwable caught) {
							handleRequestFailure(caught);
						}
					});
				}
			}
		});

	}

	public void loadGame(){
		ControllerUtils.loadGame(mediator, this);
	}

	public void exitGame() {
		ControllerUtils.logout(mediator, this);
	}

	@Override
	public void onAttachOrDetach(AttachEvent event) {
		if (event.isAttached()) {
			makeRequests();
		} else {
			// XXX anything?
		}
	}

}
